package com.jiao.datasource.proxy;

import com.jiao.datasource.listener.ListenerExce;
import com.jiao.datasource.listener.SQLListener;
import com.jiao.datasource.track.RecordSQLDetail;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;


/**
 * 代理 conn 的生命周期，生命周期为从获取连接到 close，栈结构记录sql执行.
 * @Author: vincent.jiao
 * @Date: 2021/4/16
 */
public class ConnectionProxy implements InvocationHandler {
    private Connection conn;
    public ConnectionProxy(Connection conn){
        this.conn = conn;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        boolean isExec = true;
        Object val = null;

        try {
            switch (methodName){
                case "prepareCall" :
                case "createStatement" :
                    return createStatement(proxy, method, args);

                case "prepareStatement" :
                    return prepareStatement(proxy, method, args);

                case "commit" :
                    return commit(proxy, method, args);

                case "close":
                    close(proxy, method, args);
                    break;
            }

        } catch (Exception e){
            RecordSQLDetail.clear(conn);           //清除跟踪
            throw e;
        }

        return method.invoke(conn, args);
    }

    /**
     * 提交.
     * @param proxy
     * @param method
     * @param args
     */
    public Object commit(Object proxy, Method method, Object[] args)
            throws InvocationTargetException, IllegalAccessException {
        Object val = null;
        ListenerExce.commiteBefore(RecordSQLDetail.getExceStackLsit());    //提交前通知

        val = method.invoke(conn, args);

        ListenerExce.commiteAfter(RecordSQLDetail.getExceStackLsit());    //提交后通知
        return val;
    }

    /**
     * createStatement.
     * @param proxy
     * @param method
     * @param args
     */
    public Object createStatement(Object proxy, Method method, Object[] args)
            throws InvocationTargetException, IllegalAccessException {
        Statement ps = (Statement) method.invoke(conn, args);
        InvocationHandler preparedStatementProxy = new StatementProxy(ps);
        return Proxy.newProxyInstance(ps.getClass().getClassLoader(),
                new Class[]{Statement.class}, preparedStatementProxy);
    }

    /**
     * createStatement.
     * @param proxy
     * @param method
     * @param args
     */
    public Object prepareStatement(Object proxy, Method method, Object[] args)
            throws SQLException {
        Statement ps = (PreparedStatement) conn.prepareStatement(args[0].toString(), Statement.RETURN_GENERATED_KEYS);
        InvocationHandler preparedStatementProxy = new PreparedStatementProxy(ps, args[0].toString());
        return Proxy.newProxyInstance(ps.getClass().getClassLoader(),
                new Class[]{PreparedStatement.class}, preparedStatementProxy);
    }

    /**
     * 关闭链接.
     * @param proxy
     * @param method
     * @param args
     */
    public void close(Object proxy, Method method, Object[] args)  {
        ListenerExce.close((Connection) proxy);       //通知链接关闭
        RecordSQLDetail.clear((Connection) proxy);            //清除跟踪
    }
}
